﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfLib.Craft
{
    /// <summary>
    /// CraftUc.xaml 的交互逻辑
    /// </summary>
    public partial class CraftUc : UserControl
    {
        #region 构造与拖动
        public CraftUc()
        {
            InitializeComponent();
            this.Parts = new Dictionary<string, PartUc>();

            foreach (UIElement uiEle in this.LayoutRoot.Children)
            { 
                SetMove(uiEle);
            }   
        }

        private void SetMove(UIElement uiEle)
        {
            //WPF设计上的问题,Button.Clicked事件Supress掉了Mouse.MouseLeftButtonDown附加事件等.
            //不加这个Button、TextBox等无法拖动
            if (uiEle is Button || uiEle is TextBox)
            {
                uiEle.AddHandler(Button.MouseLeftButtonDownEvent, new MouseButtonEventHandler(Element_MouseLeftButtonDown), true);
                uiEle.AddHandler(Button.MouseMoveEvent, new MouseEventHandler(Element_MouseMove), true);
                uiEle.AddHandler(Button.MouseLeftButtonUpEvent, new MouseButtonEventHandler(Element_MouseLeftButtonUp), true);

            }
            else
            {
                //
                uiEle.MouseMove += new MouseEventHandler(Element_MouseMove);
                uiEle.MouseLeftButtonDown += new MouseButtonEventHandler(Element_MouseLeftButtonDown);
                uiEle.MouseLeftButtonUp += new MouseButtonEventHandler(Element_MouseLeftButtonUp);
            }

            
        }

        bool isDragDropInEffect = false;
        Point pos = new Point();

        void Element_MouseMove(object sender, MouseEventArgs e)
        {
            if (isDragDropInEffect)
            {
                FrameworkElement currEle = sender as FrameworkElement;
                double xPos = e.GetPosition(null).X - pos.X + (double)currEle.GetValue(Canvas.LeftProperty);
                double yPos = e.GetPosition(null).Y - pos.Y + (double)currEle.GetValue(Canvas.TopProperty);
                currEle.SetValue(Canvas.LeftProperty, xPos);
                currEle.SetValue(Canvas.TopProperty, yPos);
                pos = e.GetPosition(null);

                PartUc part = currEle as PartUc;
                if (part == null)
                    return;
                foreach (Line line in part.ChildLines)
                {
                    line.X2 = Canvas.GetLeft(part);
                    line.Y2 = Canvas.GetTop(part) + 40;
                }

                foreach (Line line in part.ParentLines)
                {
                    line.X1 = Canvas.GetLeft(part) + 80;
                    line.Y1 = Canvas.GetTop(part) + 40;
                }
            }
        }

        void Element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

            FrameworkElement fEle = sender as FrameworkElement;
            isDragDropInEffect = true;
            pos = e.GetPosition(null);
            fEle.CaptureMouse();
            fEle.Cursor = Cursors.Hand;
        }

        void Element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (isDragDropInEffect)
            {
                FrameworkElement ele = sender as FrameworkElement;
                isDragDropInEffect = false;
                ele.ReleaseMouseCapture();
            }
        }

        #endregion
         
        #region Part Functions

        private double CanvasWidth { get; set; }
        private double CanvasHeight { get; set; }

        public void InitCanvas(int width, int height)
        {
            CanvasWidth = width;
            CanvasHeight = height;
        }

        public PartUc PartRoot { get; set; }

        public Dictionary<string, PartUc> Parts
        {
            get;
            private set;
        }

        /// <summary>
        /// Add Part, Please Add Root Part First.
        /// </summary>
        /// <param name="partId"></param>
        /// <param name="parentId"></param>
        /// <param name="partTitle"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void AddPart(string partId, string partTitle, string parentId = "", double x = 0, double y = 0)
        { 
            int offsetX = 20;
            int offsetY = 20;
            if (PartRoot == null && !string.IsNullOrEmpty(parentId))
                throw new ApplicationException("请先加入根部件.");

            var part = new PartUc();            

            if (PartRoot == null)
            {
                PartRoot = part;
                Canvas.SetLeft(part, x == 0 ? this.CanvasWidth - offsetX - 80  : x);
                Canvas.SetTop(part, y == 0 ? offsetY : y);
                part.Level = 1;
            }
            else
            {
                if (!Parts.ContainsKey(parentId))
                    throw new ApplicationException("无法找到父部件:"+parentId);
                var pPart = Parts[parentId];
                if(x == 0){
                    x = Canvas.GetLeft(pPart) - offsetX - 80;
                }
                Canvas.SetLeft(part,x);
                if (y == 0)
                {
                    int level = pPart.Level + 1;
                    y = this.Parts.Values.Count(p => p.Level == level) * (80 + offsetY);
                }
                Canvas.SetTop(part, y);

                part.ParentPart = pPart;
                part.Level = pPart.Level + 1;
                pPart.ChildParts.Add(part);

                //line
                Line line = new Line();
                line.X1 = x + 80;
                line.Y1 = y + 40;
                line.X2 = Canvas.GetLeft(pPart);
                line.Y2 = Canvas.GetTop(pPart) + 40;
                line.Stroke = new SolidColorBrush(Colors.Red);
                line.StrokeThickness = 1;
                part.ParentLines.Add(line);
                pPart.ChildLines.Add(line);
                this.LayoutRoot.Children.Add(line);
            }

            part.PartId = partId;
            part.Title = partTitle;
            this.LayoutRoot.Children.Add(part);
            this.Parts.Add(partId, part);
            SetMove(part);
            part.PartButton.Click += PartButton_Click;
        }

        void PartButton_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            PartUc part = btn.Tag as PartUc;
            OnShowPartInfo(part, e);
        }

        
        #endregion

        #region 事件

        public event EventHandler ShowPartInfo;

        protected virtual void OnShowPartInfo(PartUc part, EventArgs e)
        {
            if (ShowPartInfo != null)
            {
                ShowPartInfo(part, e);
            }
        }

        #endregion

        
    }
}
